﻿//======================================================================
//
//        Copyright (C) 2020-2021 个人软件工作室    
//        All rights reserved
//
//        filename :Form1.cs
//        description :
//
//        created by 张恭亮 at  2020/9/22 10:55:28
//
//======================================================================

using BasicsShape;
using FastAutomationFrame.Diagram;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace DiagramDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        

        private void diagramControl1_OnSelectElementChanged(object sender, FastAutomationFrame.Diagram.SelectElementChangedEventArgs e)
        {
            this.propertyGrid1.SelectedObject = sender;
        }

        

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "状态机文件（*.dg）|*.dg";
            sfd.FilterIndex = 1;
            sfd.RestoreDirectory = true;
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                this.diagramControl1.Save(sfd.FileName);
            }
        }
        void setDiagram(DiagramControl sonDiagram)
        {
            sonDiagram.OnEscPress += diagramControl1_OnEscPress;
            sonDiagram.OnSelectElementChanged += diagramControl1_OnSelectElementChanged;
            sonDiagram.OnSelectElementAdd += diagramControl1_OnSelectElementEntered;
            sonDiagram.Dock = DockStyle.Fill;
            foreach (ShapeBase shape in sonDiagram.ShapeCollection)
            {
                if(shape.subDiagram != null)
                {
                    setDiagram(shape.subDiagram);
                }
            }
        }
        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "状态机文件（*.dg）|*.dg";
            openFileDialog.FilterIndex = 1;
            openFileDialog.RestoreDirectory = true;
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string msg;
                if (this.diagramControl1.Import(openFileDialog.FileName, out msg))
                {
                    foreach (ShapeBase shape in this.diagramControl1.ShapeCollection)
                    {
                        if (shape.subDiagram != null)
                        {
                            setDiagram(shape.subDiagram);
                        }
                    }
                    diagramTs.Clear();
                    splitContainer1.Panel2.Controls.Clear();
                    splitContainer1.Panel2.Controls.Add(diagramControl1);
                }
            }
        }
        #region 生成代码
        private string LastSelectedFolder;
        private void toolStripLabel1_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();
            dialog.Description = "请选择保存文件夹";
            LastSelectedFolder = dialog.SelectedPath.ToString();
            dialog.SelectedPath = LastSelectedFolder;
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                generateCode(dialog.SelectedPath);
                LastSelectedFolder = dialog.SelectedPath;
            }
        }

        /**
         * 生成代码
         */

        private Dictionary<string, State> shapes = new Dictionary<string, State>();
        private Dictionary<string,SubState> subStates = new Dictionary<string,SubState>();
        private Dictionary<string, ParentState> parentStates = new Dictionary<string, ParentState>();
        private void generateCode(string path)
        {
            SaveDataInfo data = diagramControl1;
            getArray(data);
            generateCCode(path);
            generateHCode(path);
        }
        private void generateCCode(string path)
        {
            StreamWriter sw = new StreamWriter(path + "\\fsm.c", false);
            sw.WriteLine("#include \"fsm.h\"");

            #region 生成sub变量
            sw.WriteLine("unsigned char stateNow;");
            foreach (ParentState parent in parentStates.Values)
            {
                  sw.WriteLine("unsigned char " + parent.st.lowName+"_sub_now;");
            }
            #endregion
            sw.WriteLine("\r\nunsigned char get_state_now()");
            sw.WriteLine("{\r\n    return stateNow;\r\n}");
            #region 生成run函数
            foreach (State shape in shapes.Values)
            {
                sw.WriteLine("// 状态 "+shape.upName+" 下运行所需进行的操作");
                sw.WriteLine("void " + shape.lowName + "_run()\r\n{\r\n}\r\n");
            }
            foreach (SubState subState in subStates.Values)
            {
                sw.WriteLine("// 状态 " + subState.upName + " 下运行所需进行的操作");
                sw.WriteLine("void "+subState.lowName+ "_run()\r\n{\r\n}\r\n");
            }
            #endregion
            #region 生成to函数
            foreach (State shape in shapes.Values)
            {
                foreach(State toShape in shape.toState)
                {
                    sw.WriteLine("// 从状态 "+ shape.upName + " 到 "+toShape.upName+" 状态所需要进行的操作");
                    sw.WriteLine("void " + shape.lowName + "_to_" + toShape.lowName+"()\r\n{\r\n}\r\n");
                }
            }
            foreach (SubState subState in subStates.Values)
            {
                foreach (State toShape in subState.toState)
                {
                    sw.WriteLine("// 从状态 " + subState.upName + " 到 " + toShape.upName + " 状态所需要进行的操作");
                    sw.WriteLine("void " + subState.lowName + "_to_" + toShape.lowName + "()\r\n{\r\n}\r\n");
                }
            }
            #endregion
            #region 生成set函数
            sw.WriteLine("// 设置当前主状态");
            sw.WriteLine("void set_state_now(unsigned char state)\r\n{\r\n    switch (stateNow)\r\n    {");
            foreach (State shape in shapes.Values)
            {
                sw.WriteLine("        case " + shape.upName+ ":\r\n            switch (state)\r\n            {");
                foreach (State toShape in shape.toState)
                {
                    sw.WriteLine("                case " + toShape.upName + ":");
                    sw.WriteLine("                    "+shape.lowName + "_to_" + toShape.lowName + "();");
                    sw.WriteLine("                    break;");
                }

                sw.WriteLine("            }\r\n            break;");
            }
            sw.WriteLine("    }\r\n    stateNow = state;\r\n}\r\n");
            #endregion
            #region 生成subSet函数
            sw.WriteLine("// 设置当前子状态,state为所要设置的子状态的父状态名,substate为需要变更成为的子状态");
            sw.WriteLine("void set_sub_state(unsigned char state, unsigned char substate)\r\n{\r\n    switch (state)\r\n    {");
            foreach (ParentState parent in parentStates.Values)
            {
                sw.WriteLine("        case " + parent.st.upName + ":\r\n            switch(" + parent.st.lowName + "_sub_now)\r\n            {");
                
                foreach (SubState shape in parent.subStates)
                {
                    if(shape.toState.Count > 0)
                    {
                        sw.WriteLine("                case " + shape.upName + ":\r\n                    switch (substate)\r\n                    {");

                        foreach (SubState toShape in shape.toState)
                        {
                            sw.WriteLine("                        case " + toShape.upName + ":");
                            sw.WriteLine("                            " + shape.lowName + "_to_" + toShape.lowName + "();");
                            sw.WriteLine("                            break;");
                        }
                        sw.WriteLine("                    }\r\n                    break;");
                    }
                }
                sw.WriteLine("            }\r\n            "+parent.st.lowName+ "_sub_now = substate;\r\n            break;");
            }
            sw.WriteLine("    }\r\n}");
            #endregion
            #region 生成subGet函数
            sw.WriteLine("// 获取子状态,state为所要获取子状态的父状态");
            sw.WriteLine("unsigned char get_sub_state(unsigned char state)\r\n{\r\n    switch (state)\r\n    {");
            foreach (ParentState parent in parentStates.Values)
            {
                sw.WriteLine("        case "+ parent.st.upName + ":");
                sw.WriteLine("            return "+parent.st.lowName + "_sub_now;");
            }
            sw.WriteLine("    }\r\n}");
            #endregion
            #region 生成loop函数
            sw.WriteLine("// 轮询函数,需要一直掉用,可以放置在定时器中也可以放置在while(1)中");
            sw.WriteLine("void fsm_loop()\r\n{\r\n    switch (stateNow)\r\n    {");
            foreach (State shape in shapes.Values)
            {
                sw.WriteLine("        case " + shape.upName + ":\r\n            " + shape.lowName + "_run();");
                write_sub_run(sw,shape);
                sw.WriteLine("            break;");
            }
            sw.WriteLine("    }\r\n}");
           
            #endregion
            sw.Close();//写入
        }
        private void write_sub_run(StreamWriter sw,State shape)
        {
            if (parentStates.ContainsKey(shape.lowName))
            {
                ParentState parent = parentStates[shape.lowName];
                sw.WriteLine("            switch(" + parent.st.lowName + "_sub_now)\r\n            {");
                foreach (SubState subState in parent.subStates)
                {
                    sw.WriteLine("                case " + subState.upName + ":");
                    sw.WriteLine("                    " + subState.lowName + "_run();");
                    write_sub_run(sw, subState);
                    sw.WriteLine("                    break;");
                    
                }
                sw.WriteLine("            }");
            }
        }
        private void generateHCode(string path)
        {
            int i = 0;
            StreamWriter sw = new StreamWriter(path + "\\fsm.h", false);
            sw.WriteLine("#ifndef _FSM_H_");
            sw.WriteLine("#define _FSM_H_");
            #region 生成主状态enum
            sw.WriteLine("// 主状态名");
            sw.WriteLine("enum{");
            foreach (State shape in shapes.Values)
            {
                sw.WriteLine("    " + shape.upName + " = "+i.ToString()+",");
                i++;
            }
            sw.WriteLine("};\r\n");
            sw.WriteLine("// 子状态名,无论哪个层级的子状态,都会放置于这个集合体中");
            sw.WriteLine("enum{");
            i = 0;
            foreach (SubState sub in subStates.Values)
            {
                sw.WriteLine("    " + sub.upName + " = " + i.ToString() + ",");
                i++;
            }
            sw.WriteLine("};\r\n");
            #endregion
            #region 生成主状态run函数
            sw.WriteLine("// 获取当前主状态");
            sw.WriteLine("unsigned char get_state_now();\r\n");
            sw.WriteLine("// 设置当前主状态");
            sw.WriteLine("void set_state_now(unsigned char state);\r\n");
            sw.WriteLine("// 状态机轮询");
            sw.WriteLine("void fsm_loop();\r\n");
            sw.WriteLine();
            sw.WriteLine("// 设置当前子状态,state为所要设置的子状态的父状态名,substate为需要变更成为的子状态");
            sw.WriteLine("void set_sub_state(unsigned char state,unsigned char substate);\r\n");
            sw.WriteLine("// 获取子状态,state为所要获取子状态的父状态");
            sw.WriteLine("unsigned char get_sub_state(unsigned char state);\r\n");
            foreach (State shape in shapes.Values)
            {
                sw.WriteLine("// 状态 " + shape.upName + " 下运行所需进行的操作");
                sw.WriteLine("void " + shape.lowName + "_run();\r\n");
            }

            foreach (SubState sub in subStates.Values)
            {
                sw.WriteLine("// 状态 " + sub.upName + " 下运行所需进行的操作");
                sw.WriteLine("void " + sub.lowName + "_run();\r\n");
            }
            sw.WriteLine();
            #endregion
            #region 生成主状态to函数
            foreach (State shape in shapes.Values)
            {
                foreach (State toShape in shape.toState)
                {
                    sw.WriteLine("// 从状态 " + shape.upName + " 到 " + toShape.upName + " 状态所需要进行的操作");
                    sw.WriteLine("void " + shape.lowName + "_to_" + toShape.lowName + "();");
                }
            }
            sw.WriteLine();
            foreach (SubState sub in subStates.Values)
            {
                foreach (State toShape in sub.toState)
                {
                    sw.WriteLine("// 从状态 " + sub.upName + " 到 " + toShape.upName + " 状态所需要进行的操作");
                    sw.WriteLine("void " + sub.lowName + "_to_" + toShape.lowName + "();");
                }
            }
            sw.WriteLine();
            #endregion
            sw.WriteLine("#endif // !_FSM_H_\r\n");

            sw.Close();//写入
        }

        private bool getSubArray(SaveDataInfo dataInfo,State st)
        {
            bool res = true;
            if(dataInfo.Shapes.Count<=0)
            {
                return true;
            }
            ParentState parent = new ParentState(st);
            parentStates.Add(parent.st.lowName,parent);
            dataInfo.Shapes.ForEach(shape =>
            {
                if (string.IsNullOrEmpty(shape.Text))
                {
                    MessageBox.Show("每个状态都必须有状态名");
                    res = false;
                    return;
                }
                SubState state = new SubState(st,shape.Text);

                subStates.Add(shape.ObjectID, state);
                parent.subStates.Add(state);
                if (shape.SaveSubDiagram != null)
                {
                    if (getSubArray(shape.SaveSubDiagram, state) == false)
                    {
                        res = false;
                        return;
                    }
                }
            });
            if(res == false)
            {
                return false;
            }
            dataInfo.Connections.ForEach(connection =>
            {
                subStates[connection.FromContainEntityObjectID].toState.Add(subStates[connection.ToContainEntityObjectID]);
            });
            return true;
        }

        private bool getArray(SaveDataInfo dataInfo)
        {
            bool res = true;
            parentStates.Clear();
            subStates.Clear();
            shapes.Clear();
            dataInfo.Shapes.ForEach(shape =>
            {
                if(string.IsNullOrEmpty(shape.Text))
                {
                    MessageBox.Show("每个状态都必须有状态名");
                    res = false;
                    return;
                }
                State state = new State(shape.Text);
                shapes.Add(shape.ObjectID,state);
                if(shape.SaveSubDiagram != null)
                {
                    if(getSubArray(shape.SaveSubDiagram, state) == false)
                    {
                        res = false;
                        return;
                    }
                }
                
            });
            if(res == false)
            {
                return false;
            }
            dataInfo.Connections.ForEach(connection =>
            {
                shapes[connection.FromContainEntityObjectID].toState.Add(shapes[connection.ToContainEntityObjectID]);
            });
            return true;

        }
        public class State
        {
            public State(string name)
            {
                this.upName = name.ToUpper();
                this.lowName = name.ToLower();
                toState = new List<State>();
            }
            public string upName;
            public string lowName;
            public List<State> toState;
        }
        public class SubState:State
        {
            public SubState(State st,string name) : base(name)
            {
                this.upName = (st.upName + "_"+name).ToUpper();
                this.lowName = (st.lowName + "_" + name).ToLower();
                toState = new List<State>();
                parent = st;
            }
            public State parent;
        }
        public class ParentState
        {
            public State st;
            public List<SubState> subStates;
            public ParentState(State st)
            {
                this.st = st;
                subStates = new List<SubState>();
            }
        }
        #endregion

        #region 子状态
        Stack<Control> diagramTs = new Stack<Control>();
        private void diagramControl1_OnSelectElementEntered(object sender, SelectElementEnteredEventArgs e)
        {
            DiagramControl sonDiagram;
            try
            {
                ShapeBase shape = (ShapeBase)e.SelectEntity;
                if (shape == null)
                {
                    return;
                }
                if (!shape.ShapeName.Equals("SimpleRectangle"))
                {
                    return;
                }

                if (shape.subDiagram == null)
                {
                    sonDiagram = new DiagramControl();
                    shape.subDiagram = sonDiagram;
                    sonDiagram.OnEscPress += diagramControl1_OnEscPress;
                    sonDiagram.OnSelectElementChanged += diagramControl1_OnSelectElementChanged;
                    sonDiagram.OnSelectElementAdd += diagramControl1_OnSelectElementEntered;
                    sonDiagram.Dock = DockStyle.Fill;
                }
                else
                {
                    sonDiagram = (DiagramControl)shape.subDiagram;
                }
                diagramTs.Push(splitContainer1.Panel2.Controls[0]);
                ((DiagramControl)splitContainer1.Panel2.Controls[0]).OnDiagramHide();
                splitContainer1.Panel2.Controls.Clear();
                sonDiagram.OnDiagramShow();
                splitContainer1.Panel2.Controls.Add(sonDiagram);
                return;

            }
            catch (Exception exp)
            {
                return;
            }
        }
        private void diagramControl1_OnEscPress(object sender, SelectElementEnteredEventArgs e)
        {
            if (diagramTs.Count > 0)
            {
                Control temp = diagramTs.Pop();
                ((DiagramControl)splitContainer1.Panel2.Controls[0]).OnDiagramHide();
                splitContainer1.Panel2.Controls.Clear();
                splitContainer1.Panel2.Controls.Add(temp);
                ((DiagramControl)temp).OnDiagramShow();
                this.propertyGrid1.SelectedObject = ((DiagramControl)temp).GetSelected();
            }
        }
        #endregion
    }
}
